from functools import wraps
from contextlib import contextmanager
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from sqlalchemy import func
from typing import Type, TypeVar, Generic, Optional, List, Dict, Any, Union
from app.database.database import Base
from app.core.pagination import Pageable, Page
from app.utils.sql_utils import SqlUtils

# 泛型类型变量，限定为Base模型的子类
ModelType = TypeVar("ModelType", bound=Base)
import logging
logger = logging.getLogger(__name__)

def handle_db_errors(func):
    """
    数据库操作错误处理装饰器
    自动处理SQLAlchemy异常并回滚事务
    """
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        try:
            return func(self, *args, **kwargs)
        except SQLAlchemyError as e:
            self.db.rollback()  # 发生异常时自动回滚
            # 这里可以记录日志
            self.logger.error(f"Database error in {func.__name__}: {e}")
            raise e
    return wrapper

class GeneralRepository(Generic[ModelType]):
    """
    通用仓库基类，提供类似JPA的通用数据库操作方法
    支持泛型，可适用于所有数据模型
    """
    
    def __init__(self, db: Session, model: Type[ModelType]):
        """
        初始化Repository
        
        Args:
            db: 数据库会话
            model: 数据模型类，必须是Base的子类
        """
        # 类型安全检查
        if not issubclass(model, Base):
            raise TypeError(f"Model {model} must be a subclass of Base")
        self.db = db
        self.model = model
    
    @contextmanager
    def transaction(self):
        """
        事务上下文管理器
        自动处理事务提交和回滚
        
        Usage:
            with repo.transaction():
                repo.create(obj1)
                repo.create(obj2)
        """
        try:
            yield
            self.db.commit()  # 没有异常时自动提交
        except Exception:
            self.db.rollback()  # 发生异常时自动回滚
            raise
    
    # ========== 查询方法 ==========
    
    def find_all(self, *filters, order_by: Optional[Union[str, List[Union[str, object]]]] = None, limit: Optional[int] = None) -> List[ModelType]:
        """
        查询所有记录
        
        Args:
            *filters: 过滤条件，多个条件默认AND关系
            order_by: 排序字段，支持字符串、列表或字段表达式
            
        Returns:
            符合条件的记录列表
        """
        return SqlUtils.query(self.db, self.model, *filters, order_by=order_by, limit=limit).all()
    
    def find_page(self, *filters, pageable: Pageable, order_by: Optional[Union[str, List[Union[str, object]]]] = None) -> Page[ModelType]:
        """
        查询分页记录
        
        Args:
            *filters: 过滤条件
            pageable: 分页参数
            order_by: 排序字段
            
        Returns:
            分页结果对象，包含数据列表和分页信息
        """
        # 构建基础查询（不包含分页）
        # 获取总记录数
        total_count = SqlUtils.query(self.db, self.model, *filters, order_by=order_by).count()
        # 应用分页获取当前页数据
        items = SqlUtils.query(self.db, self.model, *filters, order_by=order_by, pageable=pageable).all()
        
        return Page.create(
            items=items,
            currentPage=pageable.page,
            pageSize=pageable.pageSize,
            totalCount=total_count
        )
    
    def find_by_id(self, id: int) -> Optional[ModelType]:
        """
        根据ID查询单个记录
        
        Args:
            id: 主键ID
            
        Returns:
            找到的记录对象，如果不存在返回None
        """
        return self.find_one(self.model.id == id)
    
    def find_by_ids(self, ids: List[int]) -> List[ModelType]:
        """
        根据ID列表批量查询记录
        
        Args:
            ids: 主键ID列表
            
        Returns:
            找到的记录列表
        """
        return self.find_all(self.model.id.in_(ids))
    
    def find_one(self, *filters, order_by: Optional[Union[str, List[Union[str, object]]]] = None) -> Optional[ModelType]:
        """
        根据过滤条件查询单个记录
        
        Args:
            *filters: 过滤条件
            order_by: 排序字段，对于单条记录查询，排序可用于确定返回哪条记录
            
        Returns:
            找到的第一条记录，如果不存在返回None
        """
        return SqlUtils.query(self.db, self.model, *filters, order_by=order_by).first()
    
    # ========== 写操作方法（带错误处理） ==========
    
    @handle_db_errors
    def create(self, obj: ModelType) -> ModelType:
        """
        创建新记录
        
        Args:
            obj: 要创建的模型对象
            
        Returns:
            创建后的对象（包含数据库生成的ID等字段）
        """
        self.db.add(obj)
        self.db.commit()
        self.db.refresh(obj)  # 刷新以获取数据库生成的字段值
        return obj
    
    @handle_db_errors
    def create_batch(self, objs: List[ModelType]) -> List[ModelType]:
        """
        批量创建记录
        
        Args:
            objs: 要创建的模型对象列表
            
        Returns:
            创建后的对象列表
        """
        self.db.add_all(objs)
        self.db.commit()
        # 刷新每个对象以获取数据库生成的字段值
        for obj in objs:
            self.db.refresh(obj)
        return objs
    
    @handle_db_errors
    def update(self, obj: ModelType, update_data: Dict[str, Any]) -> ModelType:
        """
        更新记录
        
        Args:
            obj: 要更新的模型对象
            update_data: 更新字段的字典
            
        Returns:
            更新后的对象
            
        Raises:
            ValueError: 当update_data中包含不存在的字段时
        """
        # 获取模型的有效字段集合
        valid_fields = {c.name for c in self.model.__table__.columns}
        
        # 只更新存在的字段
        for field, value in update_data.items():
            if field in valid_fields:
                setattr(obj, field, value)
            # else:
            #     raise ValueError(f"Field {field} does not exist in {self.model.__name__}")
        
        self.commit()
        self.refresh(obj)
        return obj
    
    @handle_db_errors
    def delete(self, obj: ModelType) -> None:
        """
        删除记录
        
        Args:
            obj: 要删除的模型对象
        """
        self.db.delete(obj)
        self.commit()
    
    @handle_db_errors
    def delete_by_id(self, id: int) -> bool:
        """
        根据ID删除记录
        
        Args:
            id: 要删除记录的主键ID
            
        Returns:
            True表示删除成功，False表示记录不存在
        """
        obj = self.find_by_id(id)
        if obj:
            self.delete(obj)
            return True
        return False
    
    # ========== 统计和检查方法 ==========
    
    def count(self, *filters) -> int:
        """
        统计记录数
        
        Args:
            *filters: 过滤条件
            
        Returns:
            符合条件的记录数量
        """
        query = self.db.query(func.count(self.model.id))
        if filters:
            query = query.filter(*filters)
        return query.scalar()  # 返回单个标量值
    
    def exists_by(self, *filters) -> bool:
        """
        检查记录是否存在
        
        Args:
            *filters: 过滤条件
            
        Returns:
            True表示存在符合条件的记录，False表示不存在
        """
        return self.find_one(*filters) is not None
    
    # ========== 数据库会话管理方法 ==========
    
    def commit(self) -> None:
        """
        提交事务
        将当前会话中的所有更改提交到数据库
        """
        self.db.commit()
    
    def refresh(self, obj: ModelType) -> None:
        """
        刷新对象状态
        从数据库重新加载对象的当前状态
        
        Args:
            obj: 要刷新的模型对象
        """
        self.db.refresh(obj)